package com.example.xcService.pojo.channels.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.xcService.pojo.channels.ChannelResult;
import com.example.xcService.pojo.channels.ChannelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;


/*
*  微涟
* */
@Slf4j
public class Plugin_ECARD_P029 implements ChannelService {

    private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
    private static final String MD5_ALGORITHM = "MD5";
    @Override
    public ChannelResult QueryBalance(JSONObject apiConfig) {
        System.out.println("成功调用了QueryBalance");
        return ChannelResult.success("success");
    }
    @Override
    public ChannelResult Submit(JSONObject apiConfig, Map<String, Object> data) {

        try {
            String accountVal = String.valueOf(data.get("AccountVal"));
            String msn = apiConfig.getString("MSN");
            String appId = apiConfig.getString("appId");

            HashMap<String, Object> submitParams = new HashMap<>();
            Instant now = Instant.now();
            long timestamp = now.getEpochSecond();
            submitParams.put("timestamp", timestamp);
            submitParams.put("productsn", data.get("SUPProductId"));
            submitParams.put("buy_num", 1);
            submitParams.put("serial_number", data.get("ChannelOrderCode"));
            submitParams.put("callback_url", apiConfig.getString("callBackUrl"));
            /*正则匹配*/
            if (isPhoneNumber(accountVal)) {
                submitParams.put("mobile", accountVal);
            } else if (isQQNumber(accountVal)) {
                submitParams.put("qq", accountVal);
            } else if (isWeChatNumber(accountVal)) {
                submitParams.put("wechat", accountVal);
            }
            String key = apiConfig.getString("appKey");
            String submitUrl = apiConfig.getString("SubmitUrl");

            String sign = generateSign(submitParams, key);
            submitParams.put("sign",sign);

            String res = sendPost(submitUrl, submitParams,msn,appId);
            log.info("微涟提单响应"+res);
            JSONObject resParams = JSONObject.parseObject(res);
            String code = resParams.getString("code");
            String message = resParams.getString("message");
            if(code.equals("0")){
                JSONObject dataParams = resParams.getObject("data", JSONObject.class);
                String status = dataParams.getString("status");
                if (status.equals("1")|| status.equals("0")||status.equals("-2")){
                    return ChannelResult.IN_PROCESS("充值中");
                }
                if (status.equals("2") ) {
                    return ChannelResult.success("充值成功");
                }
                if (status.equals("-1")){
                    return ChannelResult.FAILED("已关闭");
                }
            }
            if (code.equals("-2001")){ //订单号重复
                return ChannelResult.IN_PROCESS("充值中");
            }
            if (code.equals("-2002")||code.equals("-2003")
                    ||code.equals("-1001")||code.equals("-1002")
                    ||code.equals("-2004")||code.equals("-1006")) {
                return ChannelResult.FAILED(message);
            }
            return ChannelResult.error(message);
        }catch (Exception e) {
            e.printStackTrace();
            log.error("微涟提交订单接口错误：",e);
            return  ChannelResult.error("微涟提交订单接口错误");
        }
    }

    @Override
    public ChannelResult Query(JSONObject apiConfig, Map<String, Object> data) {

        try {
            String msn = apiConfig.getString("MSN");
            String appId = apiConfig.getString("appId");

            HashMap<String, Object> submitParams = new HashMap<>();
            Instant now = Instant.now();
            long timestamp = now.getEpochSecond();
            submitParams.put("timestamp", timestamp);
            submitParams.put("serial_number", data.get("ChannelOrderCode"));

            String key = apiConfig.getString("appKey");
            String queryUrl = apiConfig.getString("QueryUrl");

            String sign = generateSign(submitParams, key);
            submitParams.put("sign",sign);

            String res = sendGet(queryUrl, submitParams,msn,appId);
            log.info("微涟查询响应"+res);
            JSONObject resParams = JSONObject.parseObject(res);
            String code = resParams.getString("code");
            String message = resParams.getString("message");

            if(code.equals("0")){
                JSONObject dataParams = resParams.getObject("data", JSONObject.class);
                String status = dataParams.getString("status");
                if (status.equals("1")|| status.equals("0")){
                    return ChannelResult.IN_PROCESS("充值中");
                }
                if (status.equals("2")) {
                    return ChannelResult.success("充值成功");
                }
                if (status.equals("-2")) {
                    return ChannelResult.FAILED("退款/售后");
                }
                if (status.equals("-1")){
                    return ChannelResult.FAILED("充值失败");
                }
            }
            return ChannelResult.error(message);
        }catch (Exception e) {
            e.printStackTrace();
            log.error("微涟查询订单接口错误：",e);
            return  ChannelResult.error("微涟查询订单接口错误");
        }
    }

    @Override
    public ChannelResult Notify(JSONObject apiConfig, Map<String, Object> data) {
        System.out.println("成功调用了Notify");
        return ChannelResult.success("success");
    }

    public static String generateSign(Map<String, Object> params,String appKey) throws Exception {
        // 使用TreeMap对参数按照ASCII码表顺序排序
        Map<String, Object> sortedParams = new TreeMap<>(params);
        // 拼接参数串
        StringBuilder queryStringBuilder = new StringBuilder();
        for (Map.Entry<String, Object> entry : sortedParams.entrySet()) {
            queryStringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        queryStringBuilder.deleteCharAt(queryStringBuilder.length() - 1); // 删除最后一个"&"字符
        System.out.println(queryStringBuilder);

        return generateSignature(appKey,queryStringBuilder.toString());
    }


    public static String generateSignature(String appKey, String parameters)
            throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {

        String encodedString = Base64.getEncoder().encodeToString(parameters.getBytes(StandardCharsets.UTF_8));

        // Step 4: Perform HMAC-SHA1 hashing on the Base64 encoded string using appKey
        SecretKeySpec secretKeySpec = new SecretKeySpec(appKey.getBytes(StandardCharsets.UTF_8), HMAC_SHA1_ALGORITHM);
        Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
        mac.init(secretKeySpec);
        byte[] hmacBytes = mac.doFinal(encodedString.getBytes(StandardCharsets.UTF_8));

        // Step 5: Perform MD5 hashing on the HMAC-SHA1 hash bytes
        MessageDigest md = MessageDigest.getInstance(MD5_ALGORITHM);
        byte[] md5Bytes = md.digest(hmacBytes);

        // Step 6: Convert MD5 hash bytes to hexadecimal string
        StringBuilder hexString = new StringBuilder();
        for (byte b : md5Bytes) {
            hexString.append(String.format("%02x", b));
        }

        return hexString.toString();
    }

    public static String sendPost(String requestUrl, Map<String, Object> param,String username,String password) {
        InputStream inputStream = null;
        try {
            HttpClient httpClient = new HttpClient();
            PostMethod postMethod = new PostMethod(requestUrl);
            // 设置请求头  Content-Type
            postMethod.setRequestHeader("Content-Type", "application/json");
            //Base64加密方式认证方式下的basic auth HAIN460000：用户名    topicis123：密码
            postMethod.setRequestHeader("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString((username+ ":" + password).getBytes()));
            RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(param),"application/json","UTF-8");
            postMethod.setRequestEntity(requestEntity);
            httpClient.executeMethod(postMethod);// 执行请求
            inputStream =  postMethod.getResponseBodyAsStream();// 获取返回的流
            BufferedReader br = null;
            StringBuffer buffer = new StringBuffer();
            // 将返回的输入流转换成字符串
            br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String temp;
            while ((temp = br.readLine()) != null) {
                buffer.append(temp);
            }
            log.info("接口返回内容为:" + buffer);
            return buffer.toString();
        } catch (Exception e){
            log.info("请求异常" +e.getMessage());
            throw new RuntimeException(e.getMessage());
        } finally {
            if(inputStream != null) {
                try{
                    inputStream.close();
                } catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }


    private static boolean isPhoneNumber(String accountVal) {
        return accountVal.matches("\\d{11}");
    }

    private static boolean isQQNumber(String accountVal) {
        return accountVal.matches("\\d{5,12}");
    }

    private static boolean isWeChatNumber(String accountVal) {
        return accountVal.matches("^[-_a-zA-Z]{1}[-_a-zA-Z0-9]{5,19}$");
    }

    public static String sendGet(String requestUrl, Map<String, Object> param, String username, String password) {
        InputStream inputStream = null;
        try {
            // 将参数添加到URL中
            if (param != null && !param.isEmpty()) {
                StringBuilder queryBuilder = new StringBuilder("?");
                for (Map.Entry<String, Object> entry : param.entrySet()) {
                    queryBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
                }
                queryBuilder.setLength(queryBuilder.length() - 1); // 移除末尾的&
                requestUrl += queryBuilder.toString();
            }

            HttpClient httpClient = new HttpClient();
            GetMethod getMethod = new GetMethod(requestUrl);
            // 设置请求头  Content-Type
            getMethod.setRequestHeader("Content-Type", "application/json");
            // Base64加密方式认证方式下的basic auth HAIN460000：用户名    topicis123：密码
            getMethod.setRequestHeader("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString((username + ":" + password).getBytes()));
            httpClient.executeMethod(getMethod); // 执行请求
            inputStream = getMethod.getResponseBodyAsStream(); // 获取返回的流
            BufferedReader br = null;
            StringBuffer buffer = new StringBuffer();
            // 将返回的输入流转换成字符串
            br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String temp;
            while ((temp = br.readLine()) != null) {
                buffer.append(temp);
            }
            log.info("接口返回内容为:" + buffer);
            return buffer.toString();
        } catch (Exception e) {
            log.info("请求异常" + e.getMessage());
            throw new RuntimeException(e.getMessage());
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
